
#ifndef __PAISLEYPARK__LMMFACTORY_H__
#define __PAISLEYPARK__LMMFACTORY_H_

#include "Point.h"
#include <map>

template <int DIM>
class LMMMethod {
public:
	virtual void One_step_method(double _stepl) = 0;
private:
	Point<DIM>* __Pnts;
};

template <int DIM>
class ABM : public LMMMethod<DIM> {
public:
	void One_step_method(double _stepl) {
		std::cout << DIM << std::endl;
	};
private:
	Point<DIM>* _Pnts;
};

template <int DIM>
class LMMMethodFactory {
public:
	typedef LMMMethod<DIM>* (*CreateLMMCallback)();
private:
	typedef std::map<int, CreateLMMCallback> CallbackMp;
public:
	bool RegisterMethod(int MethodId, CreateLMMCallback createFn);
	bool UnregisterMethod(int MethodId);
	LMMMethod<DIM>* CreateMethod(int MethodId);
	~LMMMethodFactory(){};
	static LMMMethodFactory<DIM>* Instance() {
		if(!_obj)
			_obj = new LMMMethodFactory<DIM>;
		return _obj;
	};
//private:
	static LMMMethodFactory<DIM>* _obj;
	CallbackMp callbacks_;
	LMMMethodFactory<DIM>(){};
//	LMMMethodFactory<DIM>(const LMMMethodFactory&){};
//	LMMMethodFactory<DIM>& operator=(const LMMMethodFactory<DIM>&){};
};

template <int DIM>
LMMMethodFactory<DIM>* LMMMethodFactory<DIM>::_obj = 0;

template <int DIM>
bool LMMMethodFactory<DIM>::RegisterMethod(int MethodId, CreateLMMCallback createFn) {
	return callbacks_.insert(typename CallbackMp::value_type(MethodId, createFn)).second;
}

template <int DIM>
bool LMMMethodFactory<DIM>::UnregisterMethod(int MethodId) {
	return callbacks_.erase(MethodId) == 1;
}

template <int DIM>
LMMMethod<DIM>* LMMMethodFactory<DIM>::CreateMethod(int MethodId) {
	typename CallbackMp::const_iterator i = callbacks_.find(MethodId);
	if(i == callbacks_.end()) {
		std::cerr << "Unknown Method Id" << std::endl;
		std::exit(-1);
	}
	return (i->second)();
};

/*template <int DIM>
class TheMethodFactory : public LMMMethodFactory<DIM>{
public:
	~TheMethodFactory(){};
	static LMMMethodFactory<DIM>& Instance() {
		static LMMMethodFactory<DIM>* _obj;
		return _obj;
	};
private:
	TheMethodFactory();
	TheMethodFactory(const TheMethodFactory&){};
	TheMethodFactory& operator=(const TheMethodFactory&){};
};
*/
//template <int DIM>
//TheMethodFactory<DIM>* TheMethodFactory<DIM>::_obj = nullptr;

//class ABM : public LMMMethod<DIM>{
//public:
//	void One_step_method(Point<DIM> _p, double _stepl) {
//	/	std::cout << "ASDASDSAD" << std::endl;
//	}
//};


namespace {
	template <int DIM>
	LMMMethod<DIM>* CreateABM() {
			return new ABM<DIM>;
	}
	const int abm = 1;
#define DIM 2
	const bool registered_abm_2 = LMMMethodFactory<DIM>::Instance()->RegisterMethod(abm, CreateABM<DIM>);
#undef DIM

#define DIM 3
	const bool registered_abm_3 = LMMMethodFactory<DIM>::Instance()->RegisterMethod(abm, CreateABM<DIM>);
#undef DIM
}

//#define DIM 2
//template class LMMMethodFactory<DIM>;
//template class LMMMethod<DIM>;
//template class CreateABM<DIM>;
//template class ABM<DIM>;
//#undef DIM
#else
//Do nothing.
#endif
